package trackexplorer.views;

import java.io.File;
import java.util.LinkedList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.eclipse.core.runtime.preferences.ConfigurationScope;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.osgi.service.prefs.Preferences;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import trackexplorer.Activator;
import trackexplorer.editors.MapViewer;

public class EditDirsView extends ViewPart{
    public static final String ID      = "trackexplorer.views.EditDirsView";
    private TableViewer        viewer;
    private Action             rmElementAction;
    private Action             clickAction;
    private Action             saveAction;
    private Action[]           changeTypeActions;
    private Entries            entries = new Entries();
    private Action             addPointAction;
    private Action             showRouteAction;
    private String             file;
    private Action             newRouteAction;
    private Action             autoDirAction;
    private boolean            exportSound;
    private boolean            exportSimulator;
    private Preferences        prefs;
    class Geopos{
        double lat;
        double lon;

        public Geopos(){}

        public Geopos(double lat, double lon){
            this.lat = lat;
            this.lon = lon;
        }
    }

    class Entry{
        Geopos pos;
        String name;
        String cmt;
        int    label;

        public Entry(){}

        public Entry(Entry x){
            pos = new Geopos();
            pos.lat = x.pos.lat;
            pos.lon = x.pos.lon;
            label = 0;
        }
    }

    class Entries extends LinkedList<Entry>{
        private static final long serialVersionUID = -343441651847246653L;

        double[] getPoints(){
            double[] points = new double[size() * 2];
            int i = 0;
            for(Entry entry: entries){
                points[i++] = entry.pos.lat;
                points[i++] = entry.pos.lon;
            }
            return points;
        }

    }

    private MapViewer getActiveEditor(){
        IWorkbenchPage activePage = PlatformUI.getWorkbench()
            .getActiveWorkbenchWindow().getActivePage();
        if(activePage == null){
            return null;
        }
        IEditorPart activeEditor = activePage.getActiveEditor();
        if(activeEditor instanceof MapViewer){
            return (MapViewer)activeEditor;
        }else{
            return null;
        }
    }

    @Override
    public void dispose(){
        super.dispose();
        MapViewer mv = getActiveEditor();
        if(mv != null){
            mv.setRoute(null);
            mv.drawPoint(null);
        }
    }
    class ViewContentProvider implements IStructuredContentProvider{
        public void inputChanged(Viewer v, Object oldInput, Object newInput){}

        public void dispose(){}

        public Object[] getElements(Object parent){
            return entries.toArray();
        }
    }

    public EditDirsView(){
        prefs = new ConfigurationScope().getNode(MapViewer.ID);
        exportSound = prefs.getBoolean("exportSound", false);
        exportSimulator = prefs.getBoolean("exportSimulator", false);
    }

    private double mod(double y){
        double x = 360;
        return y - x * Math.floor(y / x);
    }
    protected static final double dtor = Math.PI / 180.0;
    protected static final double rtod = 180.0 / Math.PI;

    private double distance(double latA, double lonA, double latB, double lonB){
        return rtod
            * Math.acos(Math.sin(latA * dtor) * Math.sin(latB * dtor)
                + Math.cos(latA * dtor) * Math.cos(latB * dtor)
                * Math.cos((lonB - lonA) * dtor));
    }

    private double azimuth(double latA, double lonA, double latB, double lonB){
        double cosAzimuth = (Math.cos(latA * dtor) * Math.sin(latB * dtor) - Math
            .sin(latA * dtor)
            * Math.cos(latB * dtor) * Math.cos((lonB - lonA) * dtor))
            / Math.sin(distance(latA, lonA, latB, lonB) * dtor);

        double sinAzimuth = Math.cos(latB * dtor)
            * Math.sin((lonB - lonA) * dtor)
            / Math.sin(distance(latA, lonA, latB, lonB) * dtor);
        return rtod * Math.atan2(sinAzimuth, cosAzimuth);
    }

    public void setFile(String f){
        file = f;
        Document xmldoc;
        try{
            DocumentBuilder db = DocumentBuilderFactory.newInstance()
                .newDocumentBuilder();
            xmldoc = db.parse(f);
        }catch(Exception e){
            e.printStackTrace();
            return;
        }
        readGpx(xmldoc, "trkpt");
        readGpx(xmldoc, "rtept");
        viewer.refresh();
    }

    private void readGpx(Document xmldoc, String pt){
        NodeList trkpts = xmldoc.getElementsByTagName(pt);
        int length = trkpts.getLength();
        if(length < 1){
            return;
        }
        {
            Element trkpt = (Element)trkpts.item(0);
            Entry entry = new Entry();
            entry.pos = new Geopos();
            entry.pos.lat = Double.parseDouble(trkpt.getAttribute("lat"));
            entry.pos.lon = Double.parseDouble(trkpt.getAttribute("lon"));
            Node name = trkpt.getElementsByTagName("name").item(0);
            if(name != null){
                entry.name = name.getTextContent();
            }
            Node cmt = trkpt.getElementsByTagName("cmt").item(0);
            if(cmt != null){
                entry.cmt = cmt.getTextContent();
            }
            Node sym = trkpt.getElementsByTagName("sym").item(0);
            if(sym != null){
                entry.label = Integer.parseInt(sym.getTextContent());
            }else{
                entry.label = 1;
            }
            entries.add(entry);
        }
        for(int k = 2; k < length; k++){
            Element trkpt1 = (Element)trkpts.item(k - 2);
            Element trkpt2 = (Element)trkpts.item(k - 1);
            Element trkpt3 = (Element)trkpts.item(k);
            Entry entry = new Entry();
            Node name = trkpt2.getElementsByTagName("name").item(0);
            if(name != null){
                entry.name = name.getTextContent();
            }
            Node cmt = trkpt2.getElementsByTagName("cmt").item(0);
            if(cmt != null){
                entry.cmt = cmt.getTextContent();
            }
            double lat2 = Double.parseDouble(trkpt2.getAttribute("lat"));
            double lon2 = Double.parseDouble(trkpt2.getAttribute("lon"));
            entry.pos = new Geopos();
            entry.pos.lat = lat2;
            entry.pos.lon = lon2;
            Node sym = trkpt2.getElementsByTagName("sym").item(0);
            if(sym != null){
                try{
                    int parse = Integer.parseInt(sym.getTextContent());
                    entry.label = parse;
                }catch(NumberFormatException e){
                    entry.label = 0;
                }
            }else{
                double lat1 = Double.parseDouble(trkpt1.getAttribute("lat"));
                double lon1 = Double.parseDouble(trkpt1.getAttribute("lon"));
                double lat3 = Double.parseDouble(trkpt3.getAttribute("lat"));
                double lon3 = Double.parseDouble(trkpt3.getAttribute("lon"));
                entry.label = getLabel(new Geopos(lat1, lon1), new Geopos(lat2,
                    lon2), new Geopos(lat3, lon3));
            }
            entries.add(entry);
        }
        {
            Element trkpt = (Element)trkpts.item(length - 1);
            Entry entry = new Entry();
            entry.pos = new Geopos();
            entry.pos.lat = Double.parseDouble(trkpt.getAttribute("lat"));
            entry.pos.lon = Double.parseDouble(trkpt.getAttribute("lon"));
            Node name = trkpt.getElementsByTagName("name").item(0);
            if(name != null){
                entry.name = name.getTextContent();
            }
            Node cmt = trkpt.getElementsByTagName("cmt").item(0);
            if(cmt != null){
                entry.cmt = cmt.getTextContent();
            }
            Node sym = trkpt.getElementsByTagName("sym").item(0);
            if(sym != null){
                entry.label = Integer.parseInt(sym.getTextContent());
            }else{
                entry.label = 8;
            }
            entries.add(entry);
        }
    }

    public class ColumnProvider{
        public void createColumns(TableViewer viewer){
            String[] titles = {"Direction", "Point name", "Point comments"};
            int[] bounds = {33, 100, 150};
            int i = 0;
            TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
            column.getColumn().setText(titles[i]);
            column.getColumn().setWidth(bounds[i]);
            column.setLabelProvider(new ColumnLabelProvider(){

                @Override
                public String getText(Object o){
                    return null;
                }

                @Override
                public Image getImage(Object obj){
                    ImageRegistry imageRegistry = Activator.getDefault()
                        .getImageRegistry();
                    ImageDescriptor desc = imageRegistry.getDescriptor(String
                        .valueOf(((Entry)obj).label));
                    Image image = desc.createImage();
                    return image;
                }
            });

            i++;
            column = new TableViewerColumn(viewer, SWT.NONE);
            column.getColumn().setText(titles[i]);
            column.getColumn().setWidth(bounds[i]);
            column.setLabelProvider(new ColumnLabelProvider(){

                @Override
                public String getText(Object element){
                    return ((Entry)element).name;
                }
            });
            column.setEditingSupport(new MyEditingSupport(viewer, i));

            i++;
            column = new TableViewerColumn(viewer, SWT.NONE);
            column.getColumn().setText(titles[i]);
            column.getColumn().setWidth(bounds[i]);
            column.setLabelProvider(new ColumnLabelProvider(){

                @Override
                public String getText(Object element){
                    return ((Entry)element).cmt;
                }
            });
            column.setEditingSupport(new MyEditingSupport(viewer, i));
        }
    }
    public class MyEditingSupport extends EditingSupport{
        private CellEditor editor;
        private int        column;

        public MyEditingSupport(ColumnViewer viewer, int column){
            super(viewer);

            if(column == 0){
                editor = null;
            }else{
                editor = new TextCellEditor(((TableViewer)viewer).getTable());
            }
            this.column = column;
        }

        @Override
        protected boolean canEdit(Object element){
            return true;
        }

        @Override
        protected CellEditor getCellEditor(Object element){
            return editor;
        }

        @Override
        protected Object getValue(Object element){
            Entry entry = (Entry)element;

            switch(column){
                case 1:
                    return entry.name;
                case 2:
                    return entry.cmt;
                default:
                    break;
            }
            return null;
        }

        @Override
        protected void setValue(Object element, Object value){
            if(value instanceof String){
                Entry entry = (Entry)element;
                String val = String.valueOf(value);
                val = val.substring(0, Math.min(26, val.length()));
                switch(column){
                    case 1:
                        entry.name = val;
                        break;
                    case 2:
                        entry.cmt = val;
                        break;
                    default:
                        break;
                }
                getViewer().update(element, null);
            }
        }

    }

    @Override
    public void createPartControl(Composite parent){
        viewer = new TableViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL
            | SWT.FULL_SELECTION | SWT.MULTI);
        viewer.getTable().setHeaderVisible(true);
        viewer.getTable().setLinesVisible(true);
        viewer.setContentProvider(new ViewContentProvider());
        ColumnProvider columns = new ColumnProvider();
        columns.createColumns(viewer);
        viewer.setInput(getViewSite());
        makeActions(parent);
        hookContextMenu();
        hookClickAction();
        contributeToActionBars();
    }

    private void makeActions(final Composite parent){
        saveAction = new Action(){
            @Override
            public void run(){
                try{
                    FileDialog dialog = new FileDialog(parent.getShell(),
                        SWT.SAVE);
                    dialog.setFilterNames(new String[]{"gpx"});
                    dialog.setFilterExtensions(new String[]{"*.gpx"});
                    File file = new File(EditDirsView.this.file);
                    dialog.setFilterPath(file.getParent());
                    dialog.setFileName(file.getName());
                    String save = dialog.open();
                    if(save == null){
                        return;
                    }
                    file = new File(save);
                    Transformer transformer = TransformerFactory.newInstance()
                        .newTransformer();
                    transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
                    transformer.setOutputProperty(OutputKeys.INDENT, "yes");
                    transformer.transform(new DOMSource(getXMLDocument()),
                        new StreamResult(file));
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        };
        saveAction.setText("Save GPX file");
        saveAction.setToolTipText("Save GPX file");
        saveAction.setImageDescriptor(Activator.getDefault().getImageRegistry()
            .getDescriptor(Activator.IMG_SAVE));
        addPointAction = new Action(){
            @Override
            public void run(){
                TableItem[] selection = viewer.getTable().getSelection();
                if(selection == null || selection.length < 1){
                    return;
                }
                Entry entry = (Entry)selection[0].getData();
                if(entry == null){
                    return;
                }
                int pos = entries.indexOf(entry) + 1;
                entries.add(pos, new Entry(entry));
                viewer.refresh();
                viewer.getTable().setSelection(pos);
                clickAction.run();
            }
        };
        addPointAction.setText("Add point");
        addPointAction.setToolTipText("Add point by duplication");
        addPointAction.setImageDescriptor(Activator.getDefault()
            .getImageRegistry().getDescriptor(Activator.IMG_ADD));
        showRouteAction = new Action(){
            @Override
            public void run(){
                MapViewer mv = getActiveEditor();
                if(mv != null){
                    mv.showRoute();
                }
            }
        };
        showRouteAction.setText("Show/hide route");
        showRouteAction.setToolTipText("Show/hide route");
        showRouteAction.setImageDescriptor(Activator.getDefault()
            .getImageRegistry().getDescriptor(Activator.IMG_SHOW));
        newRouteAction = new Action(){
            @Override
            public void run(){
                MapViewer mv = getActiveEditor();
                double[] c = mv.getCenter();
                entries = new Entries();
                Entry entry = new Entry();
                entry.pos = new Geopos();
                entry.pos.lat = c[1];
                entry.pos.lon = c[0];
                entry.name = "new";
                entries.add(entry);
                file = "new.gpx";
                getActiveEditor().setRoute(entries.getPoints());
                viewer.refresh();
                viewer.getTable().setSelection(0);
                clickAction.run();
            }
        };
        newRouteAction.setText("New route");
        newRouteAction.setToolTipText("New route");
        newRouteAction.setImageDescriptor(PlatformUI.getWorkbench()
            .getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_FILE));
        autoDirAction = new Action(){
            @Override
            public void run(){
                TableItem[] selection = viewer.getTable().getSelection();
                for(int i = 0; i < selection.length; i++){
                    int index = entries.indexOf(selection[i].getData());
                    Entry entry = entries.get(index);
                    if(index == 0){
                        entry.label = 1;
                        continue;
                    }else if(index == entries.size() - 1){
                        entry.label = 8;
                        continue;
                    }
                    Entry e1 = entries.get(index - 1);
                    Entry e2 = entries.get(index + 1);
                    entry.label = getLabel(e1.pos, entry.pos, e2.pos);
                }
                viewer.refresh();
            }
        };
        autoDirAction.setText("Auto direction");
        rmElementAction = new Action(){
            @Override
            public void run(){
                TableItem[] selection = viewer.getTable().getSelection();
                if(selection == null || selection.length < 1){
                    return;
                }
                Entry entry = (Entry)selection[0].getData();
                if(entry == null){
                    return;
                }
                int pos = entries.indexOf(entry);
                entries.remove(pos);
                viewer.refresh();
                viewer.getTable().setSelection(pos);
                clickAction.run();
                MapViewer mv = getActiveEditor();
                if(mv != null){
                    mv.setRoute(entries.getPoints());
                }
                mv.drawPoint(null);
            }
        };
        rmElementAction.setToolTipText("Remove element");
        rmElementAction.setImageDescriptor(PlatformUI.getWorkbench()
            .getSharedImages()
            .getImageDescriptor(ISharedImages.IMG_TOOL_DELETE));
        clickAction = new Action(){

            @Override
            public void run(){
                TableItem[] selection = viewer.getTable().getSelection();
                MapViewer mv = getActiveEditor();
                if(mv != null && selection != null && selection.length > 0){
                    Entry entry = (Entry)selection[0].getData();
                    int[] pix = mv.getCalibration().geo2pix(entry.pos.lat,
                        entry.pos.lon);
                    mv.drawPoint(pix);
                    mv.miniNotify();
                }
            }
        };
        int MAX = 9;
        changeTypeActions = new Action[MAX];
        for(int i = 0; i < MAX; i++){
            final int n = i;
            changeTypeActions[i] = new Action(){
                @Override
                public void run(){
                    Entry entry = (Entry)((IStructuredSelection)viewer
                        .getSelection()).getFirstElement();
                    entry.label = n;
                    viewer.refresh();
                }
            };
            ImageRegistry imageRegistry = Activator.getDefault()
                .getImageRegistry();
            changeTypeActions[i].setImageDescriptor(imageRegistry
                .getDescriptor(String.valueOf(i)));
        }
    }

    private int getLabel(Geopos pos1, Geopos pos2, Geopos pos3){
        double a1 = azimuth(pos2.lat, pos2.lon, pos3.lat, pos3.lon);
        double a2 = azimuth(pos1.lat, pos1.lon, pos2.lat, pos2.lon);
        double a = mod(a1 - a2);
        int s = 1;
        if(a < 10){
            s = 1;
        }else if(a < 50){
            s = 2;
        }else if(a < 130){
            s = 4;
        }else if(a < 180){
            s = 6;
        }else if(a < 230){
            s = 7;
        }else if(a < 310){
            s = 5;
        }else if(a < 350){
            s = 3;
        }
        return s;
    }

    private void hookContextMenu(){
        MenuManager menuMgr = new MenuManager("#PopupMenu");
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new IMenuListener(){
            public void menuAboutToShow(IMenuManager manager){
                fillContextMenu(manager);
            }
        });
        Menu menu = menuMgr.createContextMenu(viewer.getControl());
        viewer.getControl().setMenu(menu);
        getSite().registerContextMenu(menuMgr, viewer);
    }

    private void fillContextMenu(IMenuManager manager){
        manager.add(rmElementAction);
        for(Action act: changeTypeActions){
            manager.add(act);
        }
        manager.add(autoDirAction);
    }

    private void hookClickAction(){
        viewer.addSelectionChangedListener(new ISelectionChangedListener(){
            public void selectionChanged(SelectionChangedEvent event){
                clickAction.run();
            }
        });
    }

    private void contributeToActionBars(){
        IActionBars bars = getViewSite().getActionBars();
        fillLocalToolBar(bars.getToolBarManager());
        fillLocalPullDown(bars.getMenuManager());
    }

    private void fillLocalPullDown(IMenuManager manager){
        Action action = new Action("Export sound", IAction.AS_CHECK_BOX){
            @Override
            public void run(){
                exportSound = !exportSound;
                prefs.putBoolean("exportSound", exportSound);
                this.setChecked(exportSound);
            }
        };
        manager.add(action);
        manager.add(new Action("Export simulator", IAction.AS_CHECK_BOX){
            @Override
            public void run(){
                exportSimulator = !exportSimulator;
                prefs.putBoolean("exportSimulator", exportSimulator);
                this.setChecked(exportSimulator);
            }
        });
    }

    private void fillLocalToolBar(IToolBarManager manager){
        manager.add(addPointAction);
        manager.add(showRouteAction);
        manager.add(newRouteAction);
        manager.add(saveAction);
    }

    @Override
    public void setFocus(){
        viewer.getControl().setFocus();
    }

    public void clickNotify(MapViewer mv, double lat, double lon){
        int[] pix = null;
        TableItem[] selection = viewer.getTable().getSelection();
        if(selection != null && selection.length > 0){
            TableItem tItem = selection[0];
            Object data = tItem.getData();
            if(data != null){
                Entry entry = (Entry)data;
                if(lat != 0. && lon != 0.){
                    entry.pos.lat = lat;
                    entry.pos.lon = lon;
                    pix = mv.getCalibration().geo2pix(entry.pos.lat,
                        entry.pos.lon);
                }
            }
        }
        mv.setRoute(entries.getPoints());
        if(pix != null){
            mv.drawPoint(pix);
        }
        mv.miniNotify();
    }

    private Document getXMLDocument() throws ParserConfigurationException{
        DocumentBuilder db = DocumentBuilderFactory.newInstance()
            .newDocumentBuilder();
        Document xmldoc = db.newDocument();
        Element gpx = xmldoc.createElement("gpx");
        //        gpx.setAttribute("version", "1.1");
        //        gpx.setAttribute("xmlns", "http://www.topografix.com/GPX/1/1");
        //        gpx.setAttribute("xmlns:xsi",
        //            "http://www.w3.org/2001/XMLSchema-instance");
        //        gpx.setAttribute("xsi:schemaLocation",
        //            "http://www.topografix.com/GPX/1/1 "
        //                + "http://www.topografix.com/GPX/1/1/gpx.xsd");
        xmldoc.appendChild(gpx);

        Element rte = xmldoc.createElement("rte");
        {
            gpx.appendChild(rte);
            Element name = xmldoc.createElement("name");
            name.setTextContent("route");
            rte.appendChild(name);
        }
        for(Entry entry: entries){
            Element rtept = xmldoc.createElement("rtept");
            rte.appendChild(rtept);
            rtept.setAttribute("lat", String.valueOf(entry.pos.lat));
            rtept.setAttribute("lon", String.valueOf(entry.pos.lon));
            Element name = xmldoc.createElement("name");
            name.setTextContent(entry.name);
            rtept.appendChild(name);
            Element cmt = xmldoc.createElement("cmt");
            cmt.setTextContent(entry.cmt);
            rtept.appendChild(cmt);
            if(exportSimulator){
                Element sym = xmldoc.createElement("sym");
                sym.setTextContent(String.valueOf(entry.label));
                rtept.appendChild(sym);
            }
            if(exportSound){
                Element sound = xmldoc.createElement("link");
                sound.setAttribute("href", entry.label + ".amr");
                rtept.appendChild(sound);
            }
        }
        return xmldoc;
    }

    public void dblClickNotify(MapViewer mapViewer, double lat, double lon){
        int pos = viewer.getTable().getSelectionIndex();
        Entry entry = new Entry();
        entry.pos = new Geopos();
        entry.pos.lat = lat;
        entry.pos.lon = lon;
        if(pos >= 0){
            entries.add(++pos, entry);
        }else{
            entries.add(entry);
            pos = viewer.getTable().getItemCount();
        }
        viewer.refresh();
        mapViewer.setRoute(entries.getPoints());
        viewer.getTable().setSelection(pos);
        clickAction.run();
    }

    public void selectEntry(double lat, double lon){
        double min = distance(lat, lon, entries.getFirst().pos.lat, entries
            .getFirst().pos.lon);
        int entry = 0;
        int pos = 0;
        for(Entry e: entries){
            double d = distance(lat, lon, e.pos.lat, e.pos.lon);
            if(min > d){
                min = d;
                entry = pos;
            }
            pos++;
        }
        viewer.getTable().setSelection(entry);
        clickAction.run();
    }
}
